package com.lintf.flowable.controller;

import com.lintf.common.base.AjaxResult;
import com.lintf.common.exception.ServiceException;
import com.lintf.common.page.BaseController;
import com.lintf.common.page.TableDataInfo;
import com.lintf.common.utils.string.StringUtils;
import com.lintf.flowable.vo.ProcessDefinitionVo;
import com.lintf.flowable.vo.ProcessInstanceVo;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.runtime.ProcessInstanceQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lin tingfeng
 * @ system Mac
 * @ data 2025/1/20 09:18
 * @ package_name com.lintf.flowable.controller
 * @ project_name sharding-sphere
 * @ desc
 */
@Slf4j
@RestController
@RequestMapping("/flowable")
public class FlowableController extends BaseController {

    private final RepositoryService repositoryService;
    private final RuntimeService runtimeService;
    private final ProcessEngine processEngine;

    @Autowired
    public FlowableController(RepositoryService repositoryService, RuntimeService runtimeService, ProcessEngine processEngine) {
        this.repositoryService = repositoryService;
        this.runtimeService = runtimeService;
        this.processEngine = processEngine;
    }


    /**
     * 查询流程定义列表
     */
    @GetMapping("/processDefinitionList")
    public TableDataInfo processDefinitionList() {
        List<ProcessDefinition> processDefinitions = repositoryService.createProcessDefinitionQuery().latestVersion().active().list();
        List<ProcessDefinitionVo> processDefinitionVos = processDefinitions.stream()
                .map(processDefinition -> new ProcessDefinitionVo(processDefinition.getDeploymentId(), processDefinition.getId(), processDefinition.getName()))
                .collect(Collectors.toList());
        return getDataTable(processDefinitionVos);
    }

    /**
     * 查询活动流程实例列表
     *
     * @param processDefinitionKey 包含查询参数的ProcessDTO
     * @return 包含流程实例列表的TableDataInfo
     */
    @GetMapping("/processList")
    public TableDataInfo processList(String processDefinitionKey) {
        ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery().orderByStartTime().desc();
        if (StringUtils.isNotEmpty(processDefinitionKey)) {
            query.processDefinitionKey(processDefinitionKey);
        }
        List<ProcessInstanceVo> processInstanceVos = query.list().stream()
                .map(FlowableController::mapToProcessInstanceVo)
                .collect(Collectors.toList());
        return getDataTable(processInstanceVos);
    }

    /**
     * 查询历史流程实例列表
     *
     * @param processDefinitionKey 包含查询参数的ProcessDTO
     * @return 包含历史流程实例列表的TableDataInfo
     */
    @GetMapping("/historyProcessList")
    public TableDataInfo historyProcessList(String processDefinitionKey) {
        HistoricProcessInstanceQuery query = processEngine.getHistoryService().createHistoricProcessInstanceQuery().orderByProcessInstanceEndTime().desc();
        if (StringUtils.isNotEmpty(processDefinitionKey)) {
            query.processDefinitionKey(processDefinitionKey);
        }
        List<ProcessInstanceVo> processInstanceVos = query.list().stream()
                .map(FlowableController::mapToProcessInstanceVo)
                .collect(Collectors.toList());
        return getDataTable(processInstanceVos);
    }

    @GetMapping("/currentNode")
    public AjaxResult getCurrentNode(String processInstanceId) {
        // 获取流程实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();

        if (processInstance == null) {
            throw new ServiceException("流程实例不存在");
        }

        // 获取所有执行对象（Execution）
        List<Execution> executions = runtimeService.createExecutionQuery()
                .processInstanceId(processInstanceId)
                .list();

        // 准备结果容器和已处理节点集合
        List<Map<String, Object>> currentNodeDetails = new ArrayList<>();
        Set<String> processedActivityIds = new HashSet<>();

        for (Execution execution : executions) {
            // 获取当前活跃的活动节点ID列表
            List<String> activeActivityIds = runtimeService.getActiveActivityIds(execution.getId());
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());

            for (String activityId : activeActivityIds) {
                if (!processedActivityIds.contains(activityId)) {
                    FlowElement flowElement = bpmnModel.getFlowElement(activityId);
                    if (flowElement != null) {
                        Map<String, Object> nodeDetail = new HashMap<>();
                        nodeDetail.put("id", activityId);
                        nodeDetail.put("name", flowElement.getName() != null ? flowElement.getName() : "无名称");
                        nodeDetail.put("type", flowElement.getClass().getSimpleName());
                        currentNodeDetails.add(nodeDetail);
                        processedActivityIds.add(activityId); // 添加到已处理集合中
                    }
                }
            }
        }

        return AjaxResult.success(currentNodeDetails);
    }

    /**
     * 删除流程实例
     *
     * @param processInstanceId 包含流程实例ID的ProcessDTO
     * @return 包含流程实例ID的AjaxResult
     */
    @PostMapping("/deleteProcess")
    public AjaxResult deleteProcess(String processInstanceId) {
        log.info("流程实例ID：" + processInstanceId);
        runtimeService.deleteProcessInstance(processInstanceId, "删除");
        return AjaxResult.success("流程实例ID：" + processInstanceId);
    }

    /**
     * 将 ProcessInstance 或 HistoricProcessInstance 映射到 ProcessInstanceVo
     *
     * @param instance 流程实例
     * @return 流程实例视图对象
     */
    public static ProcessInstanceVo mapToProcessInstanceVo(Object instance) {
        if (instance instanceof ProcessInstance) {
            ProcessInstance processInstance = (ProcessInstance) instance;
            return new ProcessInstanceVo(
                    processInstance.getId(),
                    processInstance.getBusinessStatus(),
                    processInstance.getDeploymentId(),
                    processInstance.getProcessDefinitionId(),
                    processInstance.getProcessDefinitionKey(),
                    processInstance.getProcessDefinitionName(),
                    processInstance.getStartTime()
            );
        } else if (instance instanceof HistoricProcessInstance) {
            HistoricProcessInstance processInstance = (HistoricProcessInstance) instance;
            return new ProcessInstanceVo(
                    processInstance.getId(),
                    processInstance.getBusinessStatus(),
                    processInstance.getDeploymentId(),
                    processInstance.getProcessDefinitionId(),
                    processInstance.getProcessDefinitionKey(),
                    processInstance.getProcessDefinitionName(),
                    processInstance.getStartTime()
            );
        }
        throw new IllegalArgumentException("Unsupported instance type");
    }
}
